import { PayloadAction, createAsyncThunk, createSlice } from "@reduxjs/toolkit";
import { RootState } from "./store";
import { removeElementFromArray } from "../util/Arrays";
import { getRequest } from "../util/Auth";
import { NulResponse, createRequest } from "./common";

type InvoiceType = 'retail' | 'wholesale';

interface InvoiceEntry {
  id: number;
  name: string;
  quantity: string;
  costPrice: number;
  wholesalePrice: number;
  retailPrice: number;
}

interface IssueInvoiceState {
  totalAmount: number;
  grossProfit: number;
  type: InvoiceType;
  entries: InvoiceEntry[];
  commited: boolean;
  id: string;
  date: string;
}

interface ModifyInvoiceRequest {
  id: number;
  quantity: string;
}

interface IssueInvoiceRequestEntry {
  id: number;
  quantity: number;
}

interface IssueInvoiceRequest {
  entries: IssueInvoiceRequestEntry[];
  type: InvoiceType;
  warehouseId: number;
}

interface IssueInvoiceResponse {
  id: string;
  date: string;
}

const issueInvoiceInitialState: IssueInvoiceState = {
  totalAmount: 0,
  grossProfit: 0,
  type: 'retail',
  entries: [],
  commited: false,
  id: '',
  date: ''
};

export function calculateTotalAmount(entries: InvoiceEntry[], type: InvoiceType): number {
  let result: number = 0;
  entries.forEach((value) => {
    const price: number = type === 'retail' ? value.retailPrice : value.wholesalePrice;
    result += price;
  });
  return result;
};

export function calculateGrossProfit(entries: InvoiceEntry[], type: InvoiceType): number {
  let result: number = 0;
  entries.forEach((value) => {
    const price: number = type === 'retail' ? value.retailPrice : value.wholesalePrice;
    result += price - value.costPrice;
  });
  return result;
};

const issueInvoice = createAsyncThunk('api/createIssueInvoice', async (invoice: IssueInvoiceRequest, { getState, rejectWithValue }) => {
  const state = getState() as RootState;
  try {
    const request = getRequest(state);
    const response = await request.post<NulResponse<IssueInvoiceResponse>>('/service/invoice/createEntry',
      createRequest(invoice));
    return response.data;
  }
  catch (e) {
    return rejectWithValue(e);
  }
});

const issueInvoiceSlice = createSlice({
  name: 'issueInvoice',
  initialState: issueInvoiceInitialState,
  reducers: {
    addIssueInvoice: (state, action: PayloadAction<InvoiceEntry>) => {
      const invoice: InvoiceEntry = action.payload;
      const index: number = state.entries.findIndex((value) => value.id === invoice.id);
      if (index !== -1) {
        state.entries[index].quantity += invoice.quantity;
      }
      else {
        state.entries.push(invoice);
      }
      state.totalAmount = calculateTotalAmount(state.entries, state.type);
      state.grossProfit = calculateGrossProfit(state.entries, state.type);
    },
    deleteIssueInvoice: (state, action: PayloadAction<number>) => {
      const id: number = action.payload;
      const index: number = state.entries.findIndex((value) => value.id === id);
      if (index !== -1) {
        state.entries = removeElementFromArray(state.entries, index);
      }
      state.totalAmount = calculateTotalAmount(state.entries, state.type);
      state.grossProfit = calculateGrossProfit(state.entries, state.type);
    },
    modifyIssueInvoiceQuantity: (state, action: PayloadAction<ModifyInvoiceRequest>) => {
      const request: ModifyInvoiceRequest = action.payload;
      const index: number = state.entries.findIndex((value) => value.id === request.id);
      if (index !== -1) {
        state.entries[index].quantity = request.quantity;
      }
      state.totalAmount = calculateTotalAmount(state.entries, state.type);
      state.grossProfit = calculateGrossProfit(state.entries, state.type);
    },
    switchPriceType: (state, action: PayloadAction<boolean>) => {
      state.type = action.type ? 'retail' : 'wholesale';
      state.totalAmount = calculateTotalAmount(state.entries, state.type);
      state.grossProfit = calculateGrossProfit(state.entries, state.type);
    }
  },
  extraReducers: (builder) => {
    builder.addCase(issueInvoice.rejected, (state, action) => {
      console.log(action.error);
    }).addCase(issueInvoice.fulfilled, (state, action) => {
      state.commited = true;
      state.id = action.payload.result.id;
      state.date = action.payload.result.date;
    })
  }
});

export type { InvoiceEntry, InvoiceType, IssueInvoiceRequest, IssueInvoiceRequestEntry };
export { issueInvoice };
export const { addIssueInvoice, deleteIssueInvoice, modifyIssueInvoiceQuantity, switchPriceType } = issueInvoiceSlice.actions;
export const selectIssueInvoiceTotalAmount = (state: RootState) => state.issueInvoiceReducer.totalAmount;
export const selectIssueInvoiceGrossProfit = (state: RootState) => state.issueInvoiceReducer.grossProfit;
export const selectIssueInvoiceType = (state: RootState) => state.issueInvoiceReducer.type;
export const selectIssueInvoiceEntries = (state: RootState) => state.issueInvoiceReducer.entries;
export default issueInvoiceSlice.reducer;